﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Theme3
{
    public class Program
    {
        public const string TestResultPassed = "PASSED";
        public const string TestResultError = "ERROR";

        static void Main(string[] args)
        {
            // Спецификация:

            // Геометрические чекеры TriangleChecker и RectangleChecker позволяют проверить тип Треугольника и Прямоугольника соответственно.
            // Методы проверки называются "Check", описание дано в комментариях к методам.

            // Задание:

            // Проанализировать код чекеров, выявить самостоятельно возможные классы входных и выходных данных.
            // Составить тесты для чекеров на основе Темы 3, техник Классов Эквивалентности, Граничных Значений и Попарного Тестирования.
            // - Алексей, Иван - класс "TriangleChecker", метод "TriangleCheckerTests".
            //   Совместно отвечаете за полноту тестов, проверку основных сценариев и выявление возможных ошибок.
            //   - Алексей отвечает за составление базовых тестов по Классам Эквивалентности.
            //   - Иван отвечает за составление тестов по Граничным Значениям.
            // - Стас, Данила, Сергей - класс "RectangleChecker", метод "RectangleCheckerTests".
            //   Совместно отвечаете за полноту тестов, проверку основных сценариев и выявление возможных ошибок.
            //   - Стас отвечает за составление базовых тестов по Классам Эквивалентности.
            //   - Данила отвечает за составление тестов по Граничным Значениям.
            //   - Сергей отвечает за составление тестов по Попарному Тестированию.

            // Тестирование проводится аналогично тестам из проекта Theme2.
            // Файлы с чекерами редактировать нельзя, если найдете ошибки в логики/проверках - сообщите, пожалуйста.
            // Обязательно должны быть протестированы:
            // 1. Все предполагаемые Классы Эквивалентности.
            // 2. Все предполагаемые Граничные Значения.
            // 3. Все сценарии при которых возникают исключительные ситуации.
            // Приветствуется уменьшение копипаста при написании тестов, на ваше усмотрение как это будет достигнуто.

            Console.WriteLine("-----------------------------");
            Console.WriteLine("--- TriangleCheckerTests ---");
            TriangleCheckerTests();
            Console.WriteLine("-----------------------------");

            Console.WriteLine();

            Console.WriteLine("-----------------------------");
            Console.WriteLine("--- RectangleCheckerTests ---");
            RectangleCheckerTests();
            Console.WriteLine("-----------------------------");

            Console.Read();
        }

        private static void TriangleCheckerTests()
        {
            // Тестирование по Граничным значениям
            // Тестирование по типу Равнобедренный треугольник
            TriangleCheckerTest(3, 3, 5, TriangleType.Isosceles); // Равнобедренный треугольник
            TriangleCheckerTest(4, 3, 5, TriangleType.Rectangular); // Прямоугольный треугольник
            TriangleCheckerTest(3.999, 3, 5, TriangleType.Unknown); // отнимем a на 0.001, ожидаем, что тип треугольника должен быть Неизвестным.
            TriangleCheckerTest(4.001, 3, 5, TriangleType.Unknown); // прибавим a на 0.001, ожидаем, что тип треугольника должен быть Неизвестным.

            Console.WriteLine();
            // Тестирование по типу Вырожденный треугольник
            TriangleCheckerTest(4, 3, 7, TriangleType.Degenerated); // Вырожденный треугольник.
            TriangleCheckerTest(4, 4, 7, TriangleType.Isosceles); // прибавим b на 1, ожидаем, что тип треугольника должен быть Равнобедренным.
            TriangleCheckerTest(4, 2.999, 7, TriangleType.Degenerated); // отнимем b на 0.001, ожидаем, что тип треугольника должен быть Вырожденным.
            TriangleCheckerTest(4, 3.001, 7, TriangleType.Unknown); // прибавим b на 0.001, ожидаем, что тип треугольника должен быть Неизвестным.
            TriangleCheckerTest(4, 3.999, 7, TriangleType.Unknown); // отнимем b на 0.001, ожидаем, что тип треугольника должен быть Неизвестным.
            TriangleCheckerTest(4, 4.001, 7, TriangleType.Unknown); // прибавим b на 0.001, ожидаем, что тип треугольника должен быть Неизвестным.

            Console.WriteLine();
            // Тестирование по типу Равносторонний треугольник
            TriangleCheckerTest(3, 3, 3, TriangleType.Equilateral); // Ожидаем Равносторонний треугольник
            TriangleCheckerTest(3.01, 3.01, 3.01, TriangleType.Equilateral); // Ожидаем Равносторонний треугольник

            Console.WriteLine();
            // Тестирование по типу Прямоугольный треугольник
            TriangleCheckerTest(4, 3, 5, TriangleType.Rectangular); // Прямоугольный треугольник
            TriangleCheckerTest(4, 3, 6, TriangleType.Unknown); // Неизвестный треугольник
            TriangleCheckerTest(4, 3, 4.9999, TriangleType.Unknown); // отнимем с на 0.0001, ожидаем, что тип треугольника должен быть Неизвестным
            TriangleCheckerTest(4, 3, 5.0001, TriangleType.Unknown); // Прибавим с на 0.0001, ожидаем, что тип треугольника должен быть Неизвестным

            Console.WriteLine();
            // Тестирование вызова исключения
            TriangleCheckerTest(1, -4, 3, isArgumentExceptionExpected: true); // Сделаем b отрицательным, ожидаем исключение
            TriangleCheckerTest(-1, 4, 3, isArgumentExceptionExpected: true); // Сделаем a отрицательным, ожидаем исключение
            TriangleCheckerTest(1, 4, -3, isArgumentExceptionExpected: true); // Сделаем с отрицательным, ожидаем исключение
        }

        private static void TriangleCheckerTest(double a, double b, double c, TriangleType expectedType = TriangleType.Unknown, bool isArgumentExceptionExpected = false)
        {
            TriangleChecker checker = new TriangleChecker();
            bool isArgumentExceptionHappened = false;

            try
            {
                TriangleType actualType = checker.Check(a, b, c);
                Console.WriteLine("a: {0}, b: {1}, b: {2}, Expected: {3}, Actual: {4}. Test: {5}",
                    a, b, c,
                    expectedType, actualType,
                    actualType == expectedType ? TestResultPassed : TestResultError);
            }
            catch (ArgumentException)
            {
                isArgumentExceptionHappened = true;
                Console.WriteLine("a: {0}, b: {1}, b: {2}, Expected: {3}, Actual: {4}. Test: {5}",
                    a, b, c,
                    isArgumentExceptionExpected ? "ArgumentException" : expectedType.ToString(),
                    "ArgumentException",
                    isArgumentExceptionHappened == isArgumentExceptionExpected ? TestResultPassed : TestResultError);
            }
        }

        private static void RectangleCheckerTests()
        {
            // Тестирование прямоугольников
            //Тестирование по типу Квадрат
            RectangleCheckerTests(5, 5, 90, RectangleType.Square); // Ожидаем квадрат
            RectangleCheckerTests(3.999, 5, 90, RectangleType.Rectangle); // Отнимем AC на 0.001. Ожидаем, что получится прямоугольник.
            RectangleCheckerTests(4.001, 5, 90, RectangleType.Rectangle); // Прибавим AC на 0.001 Ожидаем, что получится прямоугольник.

            Console.WriteLine();
            //Тестирование по типу Ромб 
            RectangleCheckerTests(5, 5, 89, RectangleType.Rhomb); // Ожидаем ромб
            RectangleCheckerTests(4.999, 5, 89, RectangleType.Parallelogram); // Отнимем AC на 0.001. Ожидаем, что получится параллелограмм.
            RectangleCheckerTests(5.001, 5, 89, RectangleType.Parallelogram); // Прибавим AC на 0.001. Ожидаем, что получится параллелограмм.

            Console.WriteLine();
            //Тестирование по типу Параллелограмм 
            RectangleCheckerTests(5, 6, 89, RectangleType.Parallelogram); // Ожидаем параллелограмм
            RectangleCheckerTests(5, 6, 88.999, RectangleType.Parallelogram); // Отнимем Угол на 0.001. Ожидаем, что получится параллелограмм.
            RectangleCheckerTests(5, 6, 89.001, RectangleType.Parallelogram); // Прибавим угол на 0.001. Ожидаем, что получится прямоугольник.

            Console.WriteLine();
            //Тестирование по типу Прямоугольник
            RectangleCheckerTests(5, 6, 90, RectangleType.Rectangle); // Ожидаем прямоугольник
            RectangleCheckerTests(4.999, 6, 90, RectangleType.Rectangle); // Отнимем AC на 0.001. Ожидаем, что получится квадрат.
            RectangleCheckerTests(5.001, 6, 90, RectangleType.Rectangle); // Прибавим AC на 0.001. Ожидаем, что получится прямоугольник.

            Console.WriteLine();
            // Тестирование по типу Вырожденный прямоугольник
            RectangleCheckerTests(5, 6, 0, RectangleType.Degenerated); // Ожидаем Вырожденный прямоугольник
            RectangleCheckerTests(5.001, 6, 0, RectangleType.Degenerated); // Прибавим AC 0.001. Ожидаем, что тип прямоугольника получится Неизвестным
            RectangleCheckerTests(4.999, 6, 0, RectangleType.Degenerated); // Отнимем AC 0.001. Ожидаем, что тип прямоугольника получится Неизвестным

            Console.WriteLine();
            RectangleCheckerTests(5, 6, 180, RectangleType.Degenerated); // Ожидаем Вырожденный прямоугольник
            RectangleCheckerTests(5.001, 6, 180, RectangleType.Degenerated); // Прибавим AC 0.001. Ожидаем, что тип прямоугольника получится Неизвестным
            RectangleCheckerTests(4.999, 6, 180, RectangleType.Degenerated); // Отнимем AC 0.001. Ожидаем, что тип прямоугольника получится Неизвестным

            Console.WriteLine();
            RectangleCheckerTests(5, 6, 360, RectangleType.Degenerated); // Ожидаем Вырожденный прямоугольник
            RectangleCheckerTests(5.001, 6, 360, RectangleType.Degenerated); // Прибавим AC 0.001. Ожидаем, что тип прямоугольника получится Неизвестным
            RectangleCheckerTests(4.999, 6, 360, RectangleType.Degenerated); // Отнимем AC 0.001. Ожидаем, что тип прямоугольника получится Неизвестным

            Console.WriteLine();
            // Тестирование вызова исключения
            RectangleCheckerTests(5, 6, -90, isArgumentExceptionExpected: true); // Ожидаем исключение
            RectangleCheckerTests(5, 6, 361, isArgumentExceptionExpected: true); // Ожидаем исключение
            RectangleCheckerTests(5, -6, 89, isArgumentExceptionExpected: true); // Ожидаем исключение
            RectangleCheckerTests(-5, 6, 89, isArgumentExceptionExpected: true); // Ожидаем исключение
        }

        static void RectangleCheckerTests(double ac, double bd, double abAngle, RectangleType expectedType = RectangleType.Unknown, bool isArgumentExceptionExpected = false)
        {
            RectangleChecker checker = new RectangleChecker();
            bool isArgumentExceptionHappened = false;

            try
            {
                RectangleType actualType = checker.Check(ac, bd, abAngle);
                Console.WriteLine("ac: {0}, bd: {1}, abAngle: {2}, Expected: {3}, Actual: {4}. Test: {5}",
                    ac, bd, abAngle,
                    expectedType, actualType,
                    actualType == expectedType ? TestResultPassed : TestResultError);
            }
            catch (ArgumentException)
            {
                isArgumentExceptionHappened = true;
                Console.WriteLine("ac: {0}, bd: {1}, abAngle: {2}, Expected: {3}, Actual: {4}. Test: {5}",
                    ac, bd, abAngle,
                    isArgumentExceptionExpected ? "ArgumentException" : expectedType.ToString(),
                    "ArgumentException",
                    isArgumentExceptionHappened == isArgumentExceptionExpected ? TestResultPassed : TestResultError);
            }
        }
    }
}
